using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace LightCAD.Three
{
    public class LightShadow
    {
        #region scope properties or methods
        //private static Matrix4 _projScreenMatrix = new Matrix4();
        //private static Vector3 _lightPositionWorld = new Vector3();
        //private static Vector3 _lookTarget = new Vector3();
        private static LightShadowContext getContext()
        {
            return ThreadContext.getCurrThreadContext().LightShadowCtx;
        }
        #endregion

        #region Properties

        public Camera camera;
        public double bias;
        public double normalBias;
        public double radius;
        public int blurSamples;
        public Vector2 mapSize;
        public WebGLRenderTarget map;
        public WebGLRenderTarget mapPass;
        public Matrix4 matrix;
        public bool autoUpdate;
        public bool needsUpdate;
        public Frustum _frustum;
        public Vector2 _frameExtents;
        public int _viewportCount;
        public JsArr<Vector4> _viewports;

        #endregion

        #region constructor
        public LightShadow(Camera camera = null)
        {
            this.camera = camera;
            this.bias = 0;
            this.normalBias = 0;
            this.radius = 1;
            this.blurSamples = 8;
            this.mapSize = new Vector2(512, 512);
            this.map = null;
            this.mapPass = null;
            this.matrix = new Matrix4();
            this.autoUpdate = true;
            this.needsUpdate = false;
            this._frustum = new Frustum();
            this._frameExtents = new Vector2(1, 1);
            this._viewportCount = 1;
            this._viewports = new JsArr<Vector4>{
                    new Vector4(0, 0, 1, 1)
                };
        }
        #endregion

        #region methods
        public int getViewportCount()
        {
            return this._viewportCount;
        }
        public Frustum getFrustum()
        {
            return this._frustum;
        }
        public virtual void updateMatrices(Light light, int viewportIndex = 0)
        {
            var shadowCamera = this.camera;
            var shadowMatrix = this.matrix;
            var ctx = getContext();
            var _lightPositionWorld = ctx._lightPositionWorld;
            var _lookTarget = ctx._lookTarget;
            var _projScreenMatrix = ctx._projScreenMatrix;
            _lightPositionWorld.setFromMatrixPosition(light.matrixWorld);
            shadowCamera.position.copy(_lightPositionWorld);
            _lookTarget.setFromMatrixPosition(light.target.matrixWorld);
            shadowCamera.lookAt(_lookTarget);
            shadowCamera.updateMatrixWorld();
            _projScreenMatrix.multiplyMatrices(shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse);
            this._frustum.setFromProjectionMatrix(_projScreenMatrix);
            shadowMatrix.set(
                0.5, 0.0, 0.0, 0.5,
                0.0, 0.5, 0.0, 0.5,
                0.0, 0.0, 0.5, 0.5,
                0.0, 0.0, 0.0, 1.0
            );
            shadowMatrix.multiply(_projScreenMatrix);
        }
        public Vector4 getViewport(int viewportIndex)
        {
            return this._viewports[viewportIndex];
        }
        public Vector2 getFrameExtents()
        {
            return this._frameExtents;
        }
        public void dispose()
        {
            if (this.map != null)
            {
                this.map.dispose();
            }
            if (this.mapPass != null)
            {
                this.mapPass.dispose();
            }
        }
        public LightShadow copy(LightShadow source)
        {
            this.camera = source.camera.clone();
            this.bias = source.bias;
            this.radius = source.radius;
            this.mapSize.copy(source.mapSize);
            return this;
        }
        public virtual LightShadow clone()
        {
            return new LightShadow().copy(this);
        }

        #endregion

    }
}
